﻿using System.Reflection;

using FreeSql;

using Microsoft.Extensions.DependencyInjection;

namespace Tszy.Unlimited.Data.FreeSQL;

public static class FreeSQLStartup
{
    /// <summary>
    /// 注册 FreeSQL.Mysql 库。
    /// </summary>
    /// <param name="services"></param>
    /// <param name="connectionString">数据库连接。</param>
    /// <param name="autoSyncStructure">是否自动同步实体结构到数据库，FreeSql 不会扫描程序集，只有 CRUD 时才会生成表。</param>
    /// <param name="monitorCommand">监控 SQL。</param>
    /// <returns></returns>
    public static IServiceCollection RegisterFreeSQLDotMySQL(this IServiceCollection services, string connectionString, bool autoSyncStructure = false, Action<string> monitorCommand = null)
    {
        var assemblies = GetAssemblies();

        //var freeSQL = new FreeSqlBuilder()
        //    .UseConnectionString(DataType.MySql, connectionString)
        //    .UseAutoSyncStructure(autoSyncStructure) //自动同步实体结构到数据库，FreeSql不会扫描程序集，只有CRUD时才会生成表。
        //                                             //.UseNameConvert(NameConvertType.PascalCaseToUnderscoreWithLower)
        //                                             //.UseMonitorCommand(cmd => Console.WriteLine(cmd.CommandText))
        //    .Build();

        var freeSqlBuilder = new FreeSqlBuilder();

        freeSqlBuilder.UseConnectionString(DataType.MySql, connectionString);
        freeSqlBuilder.UseAutoSyncStructure(autoSyncStructure); //自动同步实体结构到数据库，FreeSql不会扫描程序集，只有CRUD时才会生成表。

        // 监控 SQL。
        if (monitorCommand != null)
            freeSqlBuilder.UseMonitorCommand(cmd => monitorCommand.Invoke(cmd.CommandText));

        var freeSQL = freeSqlBuilder.Build();

        freeSQL.Aop.ConfigEntityProperty += (s, e) =>
        {
            if (e.Property.PropertyType.IsEnum)
                e.ModifyResult.MapType = typeof(int);
        };

        services.AddSingleton(freeSQL);
        services.AddFreeDbContext<FreeSqlDbContext>(options => options.UseFreeSql(freeSQL));
        services.AddScoped<UnitOfWorkManager>();
        services.AddScoped<IFreeSQLUnitOfWorkFactory, FreeSQLUnitOfWorkFactory>();
        services.AddFreeRepository(null, assemblies);

        services.AddScoped(typeof(IFreeSQLRepository<>), typeof(FreeSQLDefaultRepository<>));

        return services;
    }

    /// <summary>
    /// 注册 FreeSQL.Mysql 库。
    /// </summary>
    /// <typeparam name="TDatabase">用于区分不同数据库连接类型。</typeparam>
    /// <param name="services"></param>
    /// <param name="connectionString">数据库连接。</param>
    /// <param name="autoSyncStructure">是否自动同步实体结构到数据库，FreeSql 不会扫描程序集，只有 CRUD 时才会生成表。</param>
    /// <param name="monitorCommand">监控 SQL。</param>
    /// <returns></returns>
    public static IServiceCollection RegisterFreeSQLDotMySQL<TDatabase>(this IServiceCollection services, string connectionString, bool autoSyncStructure = false, Action<string> monitorCommand = null) where TDatabase : class
    {
        var freeSqlBuilder = new FreeSqlBuilder();

        freeSqlBuilder.UseConnectionString(DataType.MySql, connectionString);
        freeSqlBuilder.UseAutoSyncStructure(autoSyncStructure); //自动同步实体结构到数据库，FreeSql不会扫描程序集，只有CRUD时才会生成表。

        if (monitorCommand != null)
            freeSqlBuilder.UseMonitorCommand(cmd => monitorCommand.Invoke(cmd.CommandText));

        var freeSQL = freeSqlBuilder.Build<TDatabase>();

        services.AddSingleton(freeSQL);
        services.AddFreeDbContext<FreeSqlDbContext<TDatabase>>(options => options.UseFreeSql(freeSQL));

        return services;
    }

    private static Assembly[] GetAssemblies()
    {
        var ignore = new string[]
        {
            "Microsoft",
            "System",
            "AutoMapper",
            "Newtonsoft",
            "Serilog",
            "SixLabors",
            "RestSharp",
            "Newtonsoft",
            "MediatR",
            "Dapper",
            "CSRedis",
            "CommonMark",
            "BouncyCastle",
            "netstandard"
        };

        return AppDomain.CurrentDomain.GetAssemblies().Where(item => !ignore.Any(i => item.FullName?.StartsWith(i) ?? false)).ToArray();
    }
}